using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Net;
using System.Text;
using System.Xml;
using iPhOwa.Exchange.ContentClasses;
using iPhOwa.Exchange.ContentClasses.Fields;
using iPhOwa.Exchange.Exceptions;

namespace iPhOwa.Exchange.WebDav.Methods
{
	/// <summary>
	/// Implements the PROPFIND WebDAV method.
	/// </summary>
	internal sealed class PropFind : Method
	{
		private static readonly string[] requiredFields = new[]
		                                                  	{
		                                                  			ItemFields.ContentClass
		                                                  	};

		private readonly Collection<string> properties;

		/// <summary>
		/// Constructor.
		/// </summary>
		/// <param name="path">The exchange store path to search.</param>
		/// <param name="properties">List of properties to retrieve.</param>
		/// <param name="session">Authentication details for this session.</param>
		public PropFind(Uri path, OwaSession session, IList<string> properties) : base(path, session)
		{
			this.properties = new Collection<string>(properties);
		}

		/// <summary>
		/// List of properties to retrieve.
		/// </summary>
		public ICollection<string> Properties
		{
			get
			{
				var props = new List<string>(requiredFields);
				props.AddRange(properties);

				return props;
			}
		}

		/// <summary>
		/// The name of the method
		/// </summary>
		public override string Name
		{
			get { return "PROPFIND"; }
		}

		/// <summary>
		/// Build the command XML.
		/// </summary>
		protected override string BuildCommand()
		{
			using(var s = new EncodingStringWriter(Encoding.UTF8, CultureInfo.InvariantCulture))
			{
				using(var x = new XmlTextWriter(s))
				{
					x.Formatting = Formatting.Indented;
					x.WriteStartDocument();
					x.WriteStartElement("propfind", "DAV:");
					x.WriteStartElement("prop", "DAV:");

					foreach(string prop in Properties)
					{
						KeyValuePair<string, string> p = ParseProperty(prop);

						x.WriteStartElement(p.Value, p.Key);
						x.WriteEndElement();
					}

					x.WriteEndElement();
					x.WriteEndElement();
					x.WriteEndDocument();
				}

				StringBuilder sb = s.GetStringBuilder();

				return sb.ToString();
			}
		}

		/// <summary>
		/// Add method specific headers to request.
		/// </summary>
		protected override void AddHeaders(HttpWebRequest request)
		{
			request.Headers.Add("Depth", 0.ToString(CultureInfo.InvariantCulture));
		}

		/// <summary>
		/// Run the search.
		/// </summary>
		public Item Run()
		{
			XmlDocument document = ReadXml(Execute().GetResponseStream());

			// TODO: need to create a base MultiStatus command that search and propfind and others can inherit this common stuff...
			// HACK: shouldn't assume a:
			XmlNodeList responses = document.GetElementsByTagName("a:response");

			Item item = null;

			if(responses.Count > 0)
			{
				XmlNode response = responses[0];

				PropertyDictionary propertyHash = ReadProperties(response.ChildNodes);

				try
				{
					item = ItemFactory.Create(propertyHash[ItemFields.ContentClass]);
					item.Load(propertyHash);
				}
				catch(UnsupportedContentClassException)
				{
					// ignore unsuported types...
				}
			}

			return item;
		}
	}
}